package org.yfl.mbg.enhance.plugin;

import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.DefaultJavaFormatter;
import org.mybatis.generator.api.dom.java.*;
import org.yfl.mbg.enhance.constants.SwaggerConstants;
import org.yfl.mbg.enhance.utils.ClassUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * dto生成插件
 * @author yanfeilin
 * @version 1.0.0
 * @date 2020/5/23 19:06
 */
public class GenDtoPlugin extends PluginAdapter {

    public GenDtoPlugin() {
    }


    @Override
    public boolean validate(List<String> warnings) {
        return true;
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
        //生成dto
        String dtoTargetProject = context.getProperty("generator.dto.targetProject");
        String dtoTargetPkg = context.getProperty("generator.dto.targetPkg");
        String moduleName = getProperties().getProperty("moduleName");
        if(StringUtils.isNotEmpty(moduleName)){
            dtoTargetPkg = dtoTargetPkg.concat(".").concat(moduleName);
        }
        String dtoBaseCls = context.getProperty("generator.basedto.clsfullname");
        if(StringUtils.isEmpty(dtoTargetProject)){
            return Collections.emptyList();
        }
        List<GeneratedJavaFile> generatedJavaFileList = introspectedTable.getGeneratedJavaFiles();
        if(generatedJavaFileList == null || generatedJavaFileList.isEmpty()){
            return Collections.emptyList();
        }
        GeneratedJavaFile domainJavaFile = generatedJavaFileList.get(0);

        TopLevelClass domainLevelClass = (TopLevelClass) domainJavaFile.getCompilationUnit();
        //获取domain简类名
        String domainClsShortName = domainLevelClass.getType().getShortName().split("\\.")[0];

        //dto全类名
        String dtoClsFullName = dtoTargetPkg+"."+domainClsShortName+"Dto";
        TopLevelClass dtoLevelClass = new TopLevelClass(dtoClsFullName);

        //设置dto基本信息
        setDtoBaseInfo(dtoLevelClass,introspectedTable,dtoBaseCls);

        addDtoFields(introspectedTable,dtoLevelClass);

        addDtoSetterAndGetter(dtoLevelClass, domainLevelClass.getMethods());

        DefaultJavaFormatter javaFormatter = new DefaultJavaFormatter();
        GeneratedJavaFile dtoJavaFile = new GeneratedJavaFile(dtoLevelClass,dtoTargetProject,javaFormatter);
        List<GeneratedJavaFile> additionalJavaFileList = new ArrayList<>(5);
        additionalJavaFileList.add(dtoJavaFile);
        return additionalJavaFileList;
    }

    protected void setDtoBaseInfo(TopLevelClass dtoLevelClass,IntrospectedTable introspectedTable,String dtoBaseCls){
        //设置可见性
        dtoLevelClass.setVisibility(JavaVisibility.PUBLIC);
        dtoLevelClass.setFinal(false);

        //添加注释
        String tableRemark = introspectedTable.getRemarks();
        String dtoJavaDoc = ClassUtil.getClassJavaDoc(tableRemark+"dto");
        dtoLevelClass.addJavaDocLine(dtoJavaDoc);

        //继承基类
        if(StringUtils.isEmpty(dtoBaseCls)){
            dtoBaseCls = "java.io.Serializable";
            dtoLevelClass.addSuperInterface(new FullyQualifiedJavaType(dtoBaseCls));
        }else {
            dtoLevelClass.setSuperClass(dtoBaseCls);
        }
        dtoLevelClass.addImportedType(dtoBaseCls);

        //如果运行code generator的工程中有引入了swagger
        if(ClassUtil.isPresent(SwaggerConstants.SWAGGER_FLAG_CLASS)){
            dtoLevelClass.addImportedType(SwaggerConstants.APIMODEL_ANNO_CLASS);
            dtoLevelClass.addImportedType(SwaggerConstants.APIMODELPROPERTY_ANNO_CLASS);
            dtoLevelClass.addAnnotation("@ApiModel");
        }

        if(ClassUtil.isPresent(SwaggerConstants.JSR303_FLAG_CLASS)){
            dtoLevelClass.addImportedType(SwaggerConstants.NOTEMPTY_ANNO_CLASS);
        }
    }

    private void addSwaggerAnnotation(StringBuilder swaggerAnnoBuilder,String columnRemark,IntrospectedColumn introspectedColumn,
                                      Field field,boolean required){
        if(ClassUtil.isPresent(SwaggerConstants.SWAGGER_FLAG_CLASS)){//增加swagger注解
            swaggerAnnoBuilder.delete(0,swaggerAnnoBuilder.length());
            swaggerAnnoBuilder.append("@ApiModelProperty(value=\"").append(columnRemark)
                    .append("\"");
            if(!introspectedColumn.isNullable() && required){
                swaggerAnnoBuilder.append(", required=true)");
            }else{
                swaggerAnnoBuilder.append(")");
            }
            field.addAnnotation(swaggerAnnoBuilder.toString());
        }
    }

    protected void addDtoFields(IntrospectedTable introspectedTable,TopLevelClass dtoLevelCls){
        List<IntrospectedColumn> columnList = introspectedTable.getAllColumns();
        Field field = null;
        StringBuilder swaggerAnnoBuilder = new StringBuilder(128);
        StringBuilder notEmptyAnnoBuilder = new StringBuilder(128);
        for (IntrospectedColumn introspectedColumn : columnList) {
            String fieldName = introspectedColumn.getJavaProperty();
            String fieldTypeName = introspectedColumn.getFullyQualifiedJavaType().getShortName();
            field = new Field(fieldName,introspectedColumn.getFullyQualifiedJavaType());
            field.setVisibility(JavaVisibility.PRIVATE);
            String columnRemark = introspectedColumn.getRemarks();

            if("Date".equals(fieldTypeName)){
                dtoLevelCls.addImportedType("java.util.Date");
                Field dateStartField = new Field(fieldName+"Start",introspectedColumn.getFullyQualifiedJavaType());
                dateStartField.setVisibility(JavaVisibility.PRIVATE);
                Field dateEndField = new Field(fieldName+"End",introspectedColumn.getFullyQualifiedJavaType());
                dateEndField.setVisibility(JavaVisibility.PRIVATE);
                addSwaggerAnnotation(swaggerAnnoBuilder,columnRemark+"开始区间",introspectedColumn,dateStartField,
                        false);
                addSwaggerAnnotation(swaggerAnnoBuilder,columnRemark+"结束区间",introspectedColumn,dateEndField,false);

                dtoLevelCls.addField(dateStartField);
                dtoLevelCls.addField(dateEndField);
            }

            //增加注释
            field.addJavaDocLine(ClassUtil.getClassFieldJavaDoc(columnRemark));
            addSwaggerAnnotation(swaggerAnnoBuilder, columnRemark, introspectedColumn,field,true);


            if (!introspectedColumn.isNullable() && ClassUtil.isPresent(SwaggerConstants.JSR303_FLAG_CLASS)){//增加NotEmpty注解
                notEmptyAnnoBuilder.delete(0,notEmptyAnnoBuilder.length());

                notEmptyAnnoBuilder.append("@NotEmpty(message=\"").append(columnRemark).append("不能为空!\")");
                field.addAnnotation(notEmptyAnnoBuilder.toString());
            }

            dtoLevelCls.addField(field);
        }
    }

    protected void addDtoSetterAndGetter(TopLevelClass dtoLevelClass, List<Method> methodList){
        for (Method method : methodList) {
            dtoLevelClass.addMethod(method);
        }
    }
}
